#include "stdafx.h"
#include "XUIDragerImpl.h"

#if _IS_UI_DESIGNED_ENABLED_

#include "Util.h"
#include "UIUtil.h"

#include "IntSkinImpl.h"
#include "SkinObjMgr.h"
#include "DrawUtil.h"
#include "XTempCanvas.h"

template <class I>
CXUIDragerImpl<I>::CXUIDragerImpl()
{
    m_ImageList = NULL;
    m_pUIDragee = NULL;
    SetCursor(IDC_HAND);
    ModifyControlFlags(ESkin_Interactive, TRUE);
}

template <class I>
CXUIDragerImpl<I>::~CXUIDragerImpl()
{
}

//////////////////////////////////////////////////////////////////////////
// IXUIDrager

template <class I>
HRESULT CXUIDragerImpl<I>::put_Dragee(IN IXFrame* pUIDragee)
{
    m_pUIDragee = pUIDragee;

    if(m_pUIDragee != NULL)
    {
        m_pUIDragee->put_Margin(0, 0, 0, 0);
        m_pUIDragee->SetFrameLayoutType(FLT_VFill | FLT_HFill);
        AutoSizeImpl(FALSE);
    }
    return S_OK;
}

//////////////////////////////////////////////////////////////////////////
// IXFrame

template <class I>
BOOL CXUIDragerImpl<I>::OnMouseDown(POINT* pt)
{
    BOOL bResult = superclass::OnMouseDown(pt);
    BeginDrag(pt);
    return bResult;
}

template <class I>
BOOL CXUIDragerImpl<I>::OnMouseUp(POINT* pt)
{
    BOOL bResult = superclass::OnMouseUp(pt);
    EndDrag(TRUE);
    return bResult;
}

template <class I>
BOOL CXUIDragerImpl<I>::OnMouseMove(IN POINT* pt)
{
    IXFrame* pCurCapture = UIUtil::XGetCapture();
    if(pCurCapture == (dynamic_cast<IXFrame*>(this)))
    {
        MoveDrag(pt);
    }
    return superclass::OnMouseMove(pt);
}

template <class I>
void CXUIDragerImpl<I>::OnCaptureLost()
{
    EndDrag(FALSE);
    superclass::OnCaptureLost();
}

template <class I>
void CXUIDragerImpl<I>::PostDraw(XCANVAS xCanvas, const RECT& rcDraw)
{
    superclass::PostDraw(xCanvas, rcDraw);

    RECT rcWnd;
    get_WindowRect(&rcWnd);
    DrawUtil::Rectangle(xCanvas, &rcWnd, RGB(255, 255, 0), 1);
}

//////////////////////////////////////////////////////////////////////////
// IXControl
template <class I>
void CXUIDragerImpl<I>::GetAutoSize(OUT LPSIZE pAutoSize)
{
    if(m_pUIDragee == NULL)
        superclass::GetAutoSize(pAutoSize);
    else
        m_pUIDragee->GetAutoSize(pAutoSize);
}

template <class I>
HRESULT CXUIDragerImpl<I>::GetItemByPt(POINT& pt, IXControl** ppItem)
{
    HRESULT hResult = superclass::GetItemByPt(pt, ppItem);
    if(SUCCEEDED(hResult) && (*ppItem) != NULL)
    {
        if(dynamic_cast<IXUIDrager*>(*ppItem) == NULL)
            (*ppItem) = dynamic_cast<IXControl*>(this);
    }
    return hResult;
}

//////////////////////////////////////////////////////////////////////////
// IXBaseObj
template <class I>
void CXUIDragerImpl<I>::OnFinalRelease()
{
    superclass::OnFinalRelease();
    ReleaseData();
}

//////////////////////////////////////////////////////////////////////////
// CXUIDragerImpl

template <class I>
void CXUIDragerImpl<I>::ReleaseData()
{
    if(m_ImageList != NULL)
    {
        ImageList_Destroy(m_ImageList);
        m_ImageList = NULL;
    }
}

template <class I>
BOOL CXUIDragerImpl<I>::NeedImageList()
{
    if(m_ImageList != NULL)
        return TRUE;

    BOOL bResult = FALSE;

    RECT rcWnd;
    XIMAGE xImage = NULL;
    XIMAGE xTransImage = NULL;

    get_WindowRect(&rcWnd);

    do 
    {
        int nWidth = rcWnd.right - rcWnd.left;
        int nHeight = rcWnd.bottom - rcWnd.top;

        xImage = DrawUtil::CreateImage(24, rcWnd.right, rcWnd.bottom);
        if(xImage == NULL)
            break;
        // xTransImage = DrawUtil::CreateTransparentImage(nWidth, nHeight);

        {
            XTempCanvas canvas(xImage);
            DrawUtil::FillRect(canvas, &rcWnd, RGB(255, 0, 255));
            UIUtil::DrawControl(m_pUIDragee, canvas, NULL);
        }

        BOOL bTransOk = FALSE;
        if(xTransImage != NULL)
        {
            RECT rcTemp = rcWnd;
            ::OffsetRect(&rcTemp, -rcTemp.left, -rcTemp.top);
            XTempCanvas canvas(xTransImage);
            bTransOk = SUCCEEDED(DrawUtil::TransparentDraw(canvas, xImage, &rcWnd, &rcTemp, RGB(255, 0, 255)));
        }
        else
        {
            RECT rcTemp = rcWnd;
            ::OffsetRect(&rcTemp, -rcTemp.left, -rcTemp.top);
            XTempCanvas canvas(xImage);
            ::BitBlt((HDC)(XCANVAS)canvas, 0, 0, nWidth, nHeight, (HDC)(XCANVAS)canvas, rcWnd.left, rcWnd.top, SRCCOPY);
        }

        m_ImageList = ImageList_Create(nWidth, nHeight, bTransOk ? ILC_COLOR32 : ILC_COLOR24, 1, 1);
        if(m_ImageList == NULL)
            break;

        int nIndex = ImageList_Add(m_ImageList, (HBITMAP)(bTransOk ? xTransImage : xImage), NULL);
        XASSERT_ERROR(nIndex == 0, _T("Fuck"));

        bResult = (nIndex != -1);
    } while (FALSE);

    if(xImage != NULL)
        DrawUtil::DeleteImage(xImage);
    if(xTransImage != NULL)
        DrawUtil::DeleteImage(xTransImage);

    return bResult;
}

template <class I>
void CXUIDragerImpl<I>::BeginDrag(const POINT* ppt)
{
    if(m_pUIDragee == NULL || !NeedImageList())
        return;

    RECT rcWnd;
    m_pUIDragee->get_WindowRect(&rcWnd);

    POINT PtHotSpot = {ppt->x - rcWnd.left, ppt->y - rcWnd.top};

    BOOL bResult = ImageList_BeginDrag(m_ImageList, 0, PtHotSpot.x, PtHotSpot.y);
    if(bResult)
        bResult = ImageList_DragEnter(::GetDesktopWindow(), ppt->x, ppt->y);

    if(bResult)
    {
        InvokeEventHandler(dynamic_cast<IXControl*>(this), UIDragerEvent_BeginDrag, (LPARAM)ppt);
    }
    XASSERT_ERROR(bResult, _T("BeginDrag Failed"));
}

template <class I>
void CXUIDragerImpl<I>::MoveDrag(const POINT* ppt)
{
    POINT PtScreen = *ppt;
    ::ClientToScreen((HWND)UIUtil::GetHolderWindow(dynamic_cast<IXControl*>(this)), &PtScreen);
    BOOL bResult = ImageList_DragMove(PtScreen.x, PtScreen.y);

    if(bResult)
    {
        InvokeEventHandler(dynamic_cast<IXControl*>(this), UIDragerEvent_MoveDrag, (LPARAM)ppt);
    }
    XASSERT_ERROR(bResult, _T("BeginDrag Failed"));
}

template <class I>
void CXUIDragerImpl<I>::EndDrag(BOOL bCancel)
{
    stUIDragEndInfo info;
    info.bCancel = bCancel;
    UIUtil::XGetCurrentMsgPoint(&info.pt);
    ::ScreenToClient((HWND)UIUtil::GetHolderWindow(this), &info.pt);
    InvokeEventHandler(dynamic_cast<IXControl*>(this), UIDragerEvent_MoveDrag, (LPARAM)&info);

    ImageList_EndDrag();
}

#endif // _ENABLE_UI_DESIGNER_